package com.sec.android.app.myfiles.fragment.optimizestorage;

import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Point;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;
import android.text.format.Formatter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;

import com.sec.android.app.myfiles.R;
import com.sec.android.app.myfiles.feature.CloudMgr;
import com.sec.android.app.myfiles.feature.MultiWindowMgr;
import com.sec.android.app.myfiles.feature.MultiWindowMgr.WindowState;
import com.sec.android.app.myfiles.feature.ViEffectMgr;
import com.sec.android.app.myfiles.fragment.filelist.FileListFragment;
import com.sec.android.app.myfiles.info.AppFeatures;
import com.sec.android.app.myfiles.log.Log;
import com.sec.android.app.myfiles.log.SamsungAnalyticsLog;
import com.sec.android.app.myfiles.module.abstraction.FileRecord;
import com.sec.android.app.myfiles.module.abstraction.FileRecord.OptimizeStorageType;
import com.sec.android.app.myfiles.module.optimizestorage.OptimizeStorageAdapterImp;
import com.sec.android.app.myfiles.module.optimizestorage.OptimizeStorageAdapterImp.FilterType;
import com.sec.android.app.myfiles.module.optimizestorage.OptimizeStorageFileRecord;
import com.sec.android.app.myfiles.navigation.NavigationInfo;
import com.sec.android.app.myfiles.util.StorageMonitor;
import com.sec.android.app.myfiles.util.UiUtils;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by daesu83.kim on 2016-10-12.
 */

public class OptimizeStorageFileListFragment extends FileListFragment {

    private static final int MSG_START_CALCULATE_SELECTED_FILE_SIZE = 1000;
    private static final int MSG_DISPLAY_RESULT_SIZE = 1001;

    public enum PauseCause {
        BACKUP,
        DELETE
    }

    private OptimizeStorageType mOptimizeStorageType = OptimizeStorageType.None;
    private TextView mSubTitle;
    private TextView mSelectedFileSize;
    private final Object SIZE_UPDATE_LOCK = new Object();
    private AtomicInteger mSizeUpdateRequestId = new AtomicInteger(0);
    private SizeUpdateHandler mSizeUpdateHandler;
    private Spinner mFilter;
    private CloudMgr mCloudMgr;
    private Set<PauseCause> mPauseCauseSet = new HashSet<>();
    private boolean mFirstSelectionInvoked = false;
    private boolean mFirstSelectSavePosition = false;
    private FilterType mCurrentFilterType = FilterType.ALL;
    private boolean mFirstLoaded = false;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        OptimizeStorageFileRecord.mResultListWorking = true;
    }

    @Override
    public void onDetach() {
        super.onDetach();
        OptimizeStorageFileRecord.mResultListWorking = false;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mSizeUpdateHandler = new SizeUpdateHandler(this);
        mCloudMgr = CloudMgr.getInstance(mContext);
        mCloudMgr.addSignInStateChangeListener(mSignInStateChangeListener);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.optimize_storage_list_fragment, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mSubTitle = (TextView) view.findViewById(R.id.title);
        mSelectedFileSize = (TextView) view.findViewById(R.id.size);
        mFilter = (Spinner) view.findViewById(R.id.filter);
        mFilter.setEnabled(false);
        UiUtils.limitLargeTextSize(mContext, mSubTitle);
        UiUtils.limitLargeTextSize(mContext, mSelectedFileSize);
        ensureOptimizeStorageType();
        initSubTitle();
        setSelectedFileSize(0L);
        initFilter();
        setActionMode(ActionModeType.SELECT_FILE_FOLDER_OPERATION);
        mActivity.invalidateOptionsMenu();
        mFirstLoaded = true;
    }

    @Override
    public void onResume() {
        Log.d(this, "onResume");
        super.onResume();
    }

    @Override
    public void onPause() {
        Log.d(this, "onPause");
        super.onPause();
    }

    private void ensureOptimizeStorageType() {
        NavigationInfo info = getNavigationInfo();
        if (info != null) {
            FileRecord record = info.getCurRecord();
            if (record != null) {
                mOptimizeStorageType = OptimizeStorageFileRecord.getOptimizeStorageType(record.getFullPath());
            }
        }
    }

    private void initSubTitle() {
        String subTitle = OptimizeStorageFileRecord.getOptimizeTypeName(mContext, mOptimizeStorageType);
        if (mSubTitle != null) {
            mSubTitle.setText(subTitle);
        }
    }

    private void initFilter() {
        ArrayList<FilterItem> filterMenus = new ArrayList<>();
        mFirstSelectionInvoked = false;
        mFirstSelectSavePosition = false;
        switch (mOptimizeStorageType) {
            case LargeFiles:
                filterMenus.add(new FilterItem(FilterType.ALL, getString(R.string.all)));
                filterMenus.add(new FilterItem(FilterType.VIDEO_ONLY, getString(R.string.video_only)));
                filterMenus.add(new FilterItem(FilterType.IMAGE_ONLY, getString(R.string.image_only)));
                filterMenus.add(new FilterItem(FilterType.AUDIO_ONLY, getString(R.string.audio_only)));
                filterMenus.add(new FilterItem(FilterType.DOCUMENT_ONLY, getString(R.string.document_only)));
                filterMenus.add(new FilterItem(FilterType.CONTENTS_TYPE_OTHERS, getString(R.string.other_files)));
//                SamsungAnalyticsLog.setScreenInfo(SamsungAnalyticsLog.ScreenPath.GET_MORE_SPACE_LARGE);    // TODO : HJ SA
                break;

            case UnusedFiles:
                filterMenus.add(new FilterItem(FilterType.ALL, getString(R.string.all)));
                filterMenus.add(new FilterItem(FilterType.VIDEO_ONLY, getString(R.string.video_only)));
                filterMenus.add(new FilterItem(FilterType.IMAGE_ONLY, getString(R.string.image_only)));
                filterMenus.add(new FilterItem(FilterType.AUDIO_ONLY, getString(R.string.audio_only)));
                filterMenus.add(new FilterItem(FilterType.DOCUMENT_ONLY, getString(R.string.document_only)));
//                SamsungAnalyticsLog.setScreenInfo(SamsungAnalyticsLog.ScreenPath.GET_MORE_SPACE_UNUSED);  // TODO : HJ SA
                break;

            case DuplicateFiles:
                filterMenus.add(new FilterItem(FilterType.ALL, getString(R.string.all)));
                filterMenus.add(new FilterItem(FilterType.INTERNAL_STORAGE, getString(R.string.my_device)));
                filterMenus.add(new FilterItem(FilterType.SD_CARD, getString(R.string.sd_card)));
                if (UiUtils.isCloudGatewayEnabled(mContext)) {
                    filterMenus.add(new FilterItem(FilterType.CLOUD, getString(R.string.cloud_storage)));
                }
//                SamsungAnalyticsLog.setScreenInfo(SamsungAnalyticsLog.ScreenPath.GET_MORE_SPACE_DUPLICATE); // TODO : HJ SA
                break;
            case UnnecessaryData:
//                SamsungAnalyticsLog.setScreenInfo(SamsungAnalyticsLog.ScreenPath.GET_MORE_SPACE_UNNECESSARY);   // TODO : HJ SA
                break;
        }
        if (!filterMenus.isEmpty()) {
            ArrayAdapter<FilterItem> adapter = new ArrayAdapter<FilterItem>(getActivity(),
                    R.layout.spinner_item, filterMenus) {
                @Override
                public long getItemId(int position) {
                    int ret = 0;
                    FilterItem item = getItem(position);
                    if (item != null) {
                        ret = item.mFilterType.ordinal();
                    }
                    return ret;
                }

                @NonNull
                @Override
                public View getView(int position, View convertView, ViewGroup parent) {
                    View view = super.getView(position, convertView, parent);
                    if (view instanceof TextView && convertView == null) {
                        UiUtils.limitLargeTextSize(mContext, (TextView) view);
                    }
                    return view;
                }

                @Override
                public View getDropDownView(int position, View convertView, ViewGroup parent) {
                    View view = super.getDropDownView(position, convertView, parent);
                    if (view instanceof TextView && convertView == null) {
                        UiUtils.limitLargeTextSize(mContext, (TextView) view);
                    }
                    return view;
                }
            };
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            mFilter.setOnItemSelectedListener(mFilterItemSelectedListener);
            mFilter.setAdapter(adapter);
        } else {
            mFilter.setVisibility(View.GONE);
        }
    }

    @Override
    public boolean hasSubTitle() {
        return true;
    }

    @Override
    protected boolean _onItemClick(FileRecord record) {
        // DO NOTHING. Always edit mode.
        return false;
    }

    @Override
    public void onCheckedItemChanged() {
        super.onCheckedItemChanged();
        clearSizeUpdateEvent();
        Message msg = mSizeUpdateHandler.obtainMessage(MSG_START_CALCULATE_SELECTED_FILE_SIZE);
        msg.arg1 = mSizeUpdateRequestId.incrementAndGet();
        mSizeUpdateHandler.sendMessage(msg);
    }

    private void setSelectedFileSize(long size) {
        if (mSelectedFileSize != null) {
            mSelectedFileSize.setText(String.format(Locale.getDefault(),
                    "(%s)", Formatter.formatFileSize(mContext, size)));
        }
        if (mFilter != null) {
            mFilter.requestLayout();
        }

        refreshTextViewWidth();
    }

    @Override
    public void setLoadingView() {
        super.setLoadingView();
        if (mFilter != null) {
            mFilter.setEnabled(false);
        }
        if (mListViewImp != null) {
            mListViewImp.clearChoices();
        }
        updateActionBarMenu();
    }

    @Override
    public void onMediaUnmounted(String path) {
        super.onMediaUnmounted(path);
        if (StorageMonitor.isRemovedExtSDCard(path)) {
            _onContentChanged(0);
        }
    }

    @Override
    public void onMediaScanFinish() {
        super.onMediaScanFinish();
        if (mPauseCauseSet.isEmpty()) {
            _onContentChanged(0);
        }
        resumeReload(PauseCause.DELETE);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mSizeUpdateRequestId.set(-1);
        clearSizeUpdateEvent();
        mCloudMgr.removeSignInStateChangeListener(mSignInStateChangeListener);
        if (mAdapter != null) {
            mAdapter.destroyLoader();
        }
    }

    private void clearSizeUpdateEvent() {
        mSizeUpdateHandler.removeMessages(MSG_START_CALCULATE_SELECTED_FILE_SIZE);
        mSizeUpdateHandler.removeMessages(MSG_DISPLAY_RESULT_SIZE);
    }

    @Override
    public int getTotalFileCount() {
        int ret = 0;
        if (mAdapter != null) {
            Cursor cursor = mAdapter.getCursor();
            if (cursor != null && !cursor.isClosed()) {
                ret = cursor.getCount();
            }
        }
        return ret;
    }

    @Override
    public long getTotalFileSize() {
        long totalFileSize = 0;
        int itemCount = mAdapter.getItemCount();
        for (int i = 0; i < itemCount; i++) {
            FileRecord record = getFileRecord(i);
            if (record != null) {
                totalFileSize += record.getSize();
            }
        }
        return totalFileSize;
    }

    @Override
    protected void _onContentChanged(int event) {
        Log.d(this, "_onContentChanged");
        ((OptimizeStorageAdapterImp) mAdapter.getAdapterImp()).needRefresh();
        super._onContentChanged(event);
    }

    public void reload(boolean reloadOptimizeStorageDb) {
        if (reloadOptimizeStorageDb) {
            ((OptimizeStorageAdapterImp) mAdapter.getAdapterImp()).needRefresh();
        }
        reload();
    }

    @Override
    public void onLoadFinished() {
        super.onLoadFinished();
        if (mFilter != null) {
            mFilter.setEnabled(true);
        }
        selectAll(false);
        mListViewImp.clearChoices();
        setSelectedFileSize(0L);
        updateActionBarMenu();

        if (mFirstLoaded) {
            mFirstLoaded = false;
            setDefaultSelection();
        }
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (mListViewImp.getCount() == 0) {
            if (mCurrentFilterType == FilterType.ALL) {
                UiUtils.replaceFragment(this);
            }
        }

        refreshTextViewWidth();
    }

    @Override
    protected View _setEmptyView(ViewGroup root) {
        View ret = null;
        int layoutResId = R.layout.get_more_space_no_item;
        if (mCurrentFilterType == FilterType.ALL) {
            WindowState windowState = MultiWindowMgr.getInstance(mActivity, mProcessId).getWindowState();
            if (!AppFeatures.isTabletUIMode() && windowState == WindowState.LANDSCAPE) {
                layoutResId = R.layout.get_more_space_no_item_land;
            }
        } else {
            layoutResId = R.layout.no_item;
        }

        ViewGroup parent = null;
        ViewGroup.LayoutParams layoutParams = null;
        View emptyViewStub = root.findViewById(R.id.empty_view_stub);
        if (emptyViewStub != null) {
            parent = (ViewGroup) emptyViewStub.getParent();
            parent.removeView(emptyViewStub);
            layoutParams = emptyViewStub.getLayoutParams();
        }
        View emptyView = root.findViewById(R.id.empty_view);
        if (emptyView != null) {
            parent = (ViewGroup) emptyView.getParent();
            parent.removeView(emptyView);
            layoutParams = emptyView.getLayoutParams();
        }
        if (parent != null) {
            ret = root.inflate(mContext, layoutResId, null);
            ret.setId(R.id.empty_view);
            parent.addView(ret, layoutParams);
        }
        return ret;
    }

    @Override
    protected void ensureEmptyView(View emptyView) {
        OptimizeStorageAdapterImp adapterImp = (OptimizeStorageAdapterImp) mAdapter.getAdapterImp();
        if (adapterImp.getFilterType() == FilterType.ALL) {
            TextView usageTextView = (TextView) emptyView.findViewById(R.id.storage_usage);
            Activity activity = getActivity();
            if (usageTextView != null && activity != null) {
                long totalSize = StorageMonitor.getInternalTotalSize(mContext);
                long freeSpace = StorageMonitor.getStorageFreeSpace(activity, StorageMonitor.iStorageType.INTERNAL);
                String total = Formatter.formatShortFileSize(activity, totalSize);
                String used = Formatter.formatFileSize(activity, totalSize - freeSpace);
                String text = used + " / " + total;
                usageTextView.setText(text);
            }
            ViEffectMgr.getInstance().showGmsEmptyView(emptyView);
        } else {
            mListViewImp.setEmptyView(null);
            super.ensureEmptyView(emptyView);
        }
    }

    public void pauseReload(PauseCause cause) {
        if (cause != null) {
            mPauseCauseSet.add(cause);
        }
    }

    public void resumeReload(PauseCause cause) {
        if (cause != null) {
            mPauseCauseSet.remove(cause);
        }
    }

    public FilterType getFilter() {
        return ((OptimizeStorageAdapterImp) mAdapter.getAdapterImp()).getFilterType();
    }

    public boolean setFilter(FilterType filterType) {
        boolean ret = false;
        int filterCount = mFilter.getCount();
        FilterItem item;
        for (int i = 0; i < filterCount; i++) {
            item = (FilterItem) mFilter.getItemAtPosition(i);
            if (item.mFilterType == filterType) {
                OptimizeStorageAdapterImp adapterImp = (OptimizeStorageAdapterImp) mAdapter.getAdapterImp();
                ret = true;
                adapterImp.setFilterType(filterType);
                mFilter.setSelection(i);
                mFilter.setEnabled(false);
                selectAll(false);
                reload();
                setSelectedFileSize(0L);

                SamsungAnalyticsLog.sendLog(getProcessId(), SamsungAnalyticsLog.Event.FILTER, item.toString(), null);
                mCurrentFilterType = filterType;
                mFirstLoaded = true;
                break;
            }
        }
        return ret;
    }

    @Override
    public void setNavigationInfo(NavigationInfo navigationInfo) {
        if (navigationInfo != null) {
            navigationInfo.showLoadingView(true);
        }
        super.setNavigationInfo(navigationInfo);
    }

    public void setNeedRefresh(boolean needRefresh) {
        mNavigationInfo.showLoadingView(needRefresh);
        ((OptimizeStorageAdapterImp) mAdapter.getAdapterImp()).setNeedRefresh(needRefresh);
    }

    private static class SizeUpdateHandler extends Handler {
        private WeakReference<OptimizeStorageFileListFragment> mParent;

        public SizeUpdateHandler(OptimizeStorageFileListFragment fragment) {
            mParent = new WeakReference<>(fragment);
        }

        @Override
        public void handleMessage(Message msg) {
            OptimizeStorageFileListFragment fragment = mParent.get();
            if (fragment != null) {
                switch (msg.what) {
                    case MSG_START_CALCULATE_SELECTED_FILE_SIZE:
                        List<FileRecord> selectedFile = fragment.getSelectedFile();
                        if (selectedFile != null && !selectedFile.isEmpty()) {
                            new SizeCalculateThread(fragment, msg.arg1, selectedFile).start();
                        } else {
                            fragment.setSelectedFileSize(0L);
                        }
                        break;

                    case MSG_DISPLAY_RESULT_SIZE:
                        fragment.setSelectedFileSize((Long) msg.obj);
                        break;
                }
            }
        }
    }

    private static class SizeCalculateThread extends Thread {
        private WeakReference<OptimizeStorageFileListFragment> mParent;
        private int mSizeRequestId;
        private List<FileRecord> mSelectedFiles;

        public SizeCalculateThread(OptimizeStorageFileListFragment parent, int sizeRequestId,
                                   List<FileRecord> selectedFiles) {
            mParent = new WeakReference<>(parent);
            mSizeRequestId = sizeRequestId;
            mSelectedFiles = selectedFiles;
        }

        @Override
        public void run() {
            long totalSize = 0L;
            if (mSelectedFiles != null && !mSelectedFiles.isEmpty()) {
                boolean completed = true;
                for (FileRecord record : mSelectedFiles) {
                    if (!keepGoing()) {
                        completed = false;
                        break;
                    }
                    if (record != null) {
                        totalSize += record.getSize();
                    }
                }
                if (completed) {
                    OptimizeStorageFileListFragment fragment = mParent.get();
                    if (fragment != null) {
                        synchronized (fragment.SIZE_UPDATE_LOCK) {
                            Message msg = fragment.mSizeUpdateHandler.obtainMessage(MSG_DISPLAY_RESULT_SIZE);
                            msg.obj = totalSize;
                            fragment.mSizeUpdateHandler.sendMessage(msg);
                        }
                    }
                }
            }
        }

        private boolean keepGoing() {
            boolean ret = false;
            OptimizeStorageFileListFragment fragment = mParent.get();
            if (fragment != null) {
                ret = fragment.mSizeUpdateRequestId.get() == mSizeRequestId;
            }
            return ret;
        }
    }

    private AdapterView.OnItemSelectedListener mFilterItemSelectedListener = new AdapterView.OnItemSelectedListener() {
        // onItemSelected() is invoked when it is added to spinner.
        // prevent first selection because it cause duplicated invocation of initLoader().

        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            if (!mFirstSelectionInvoked) {
                if (position == 0 || mFirstSelectSavePosition) {
                    mFirstSelectionInvoked = true;
                } else {
                    mFirstSelectSavePosition = true;
                }
            } else {
                FilterType filterType = FilterType.ALL;
                FilterType[] filterTypes = FilterType.values();
                if (0 <= id && id < filterTypes.length) {
                    filterType = filterTypes[(int) id];
                }
                setFilter(filterType);
            }

            refreshTextViewWidth();
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
        }
    };

    private static class FilterItem {
        public FilterType mFilterType;
        public String mText;

        public FilterItem(FilterType filterType, String text) {
            mFilterType = filterType;
            mText = text;
        }

        @Override
        public String toString() {
            return mText;
        }
    }

    private CloudMgr.OnSignInStateChangeListener mSignInStateChangeListener = new CloudMgr.OnSignInStateChangeListener() {
        @Override
        public void onSignInStateChanged(FileRecord.CloudType cloudType, boolean signedIn) {
            if (mOptimizeStorageType == OptimizeStorageType.DuplicateFiles) {
                _onContentChanged(0);
            }
        }
    };

    private int getScreenWidth() {
        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        Point size = new Point();
        wm.getDefaultDisplay().getSize(size);
        return size.x;
    }

    private int getWidthTextView(TextView textView) {
        int screenWidth = getScreenWidth();
        int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(screenWidth, View.MeasureSpec.AT_MOST);
        int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        textView.measure(widthMeasureSpec, heightMeasureSpec);
        return textView.getMeasuredWidth();
    }

    private void refreshTextViewWidth() {
        int textViewMarginStart = mContext.getResources().getDimensionPixelSize(R.dimen.optimize_storage_list_sub_header_size_margin_start);
        int spinnerMarginEnd = mContext.getResources().getDimensionPixelSize(R.dimen.optimize_storage_list_sub_header_spinner_margin_end);
        int textTitleMarginStart = mContext.getResources().getDimensionPixelSize(R.dimen.optimize_storage_list_sub_header_title_margin_start);
        int screenWidth = getScreenWidth();
        int textSizeWidth = getWidthTextView(mSelectedFileSize);

        int maxWidth = screenWidth - (textTitleMarginStart + spinnerMarginEnd + textViewMarginStart + textSizeWidth + mFilter.getWidth());
        mSubTitle.setMaxWidth(maxWidth);
    }
}
